﻿namespace ColorizerEditor

open System.Windows
open System.Windows.Controls
open System.Windows.Data
open System.Windows.Media
open System.Windows.Shapes
open Microsoft.Win32 
open System.Collections.Generic
open System.ComponentModel
open ColorPickerControl
open System.Windows.Input
open System.Windows.Media.Imaging
open System.IO
open System.Text
open System
open System.Security.AccessControl
open System.Xml.Linq

[<AutoOpen>]
module Utility =    
    let showMessage(text,caption) =
        MessageBox.Show(text,caption,MessageBoxButton.OK,MessageBoxImage.Information) |> ignore

    let showError(text) =
        MessageBox.Show(text, "Error", MessageBoxButton.OK, MessageBoxImage.Error) |> ignore

    let showWarning(text) =
        MessageBox.Show(text, "Warning" ,MessageBoxButton.OK,MessageBoxImage.Warning) |> ignore

    let askQuestion(text,caption) = 
        MessageBox.Show(text, caption, MessageBoxButton.YesNo, MessageBoxImage.Question)

[<AutoOpen>]
module App =                   
    type Commands() =                    
        static let mutable applyCommand = new RoutedUICommand("Apply", "Apply", typeof<Commands>)     
        static member ApplyCommand = applyCommand
                
    type MainWindow() as self=
        inherit Window()                

        let edgeColorPicker = new ColorPicker (Margin=Thickness(5.,0.,5.,0.))
        let mainColorPicker = new ColorPicker(Margin=Thickness(5.,0.,5.,0.))   
        let rightPane = new Canvas()    
        let fileExplorerTree = new TreeView(Height=600.)    
        let rootItem = new TreeViewItem(Header = "Color Files", IsExpanded = true)
        let mutable isDirty = true
        let mutable currentSavePath = String.Empty
        let rects = new List<_>()
        let title = "F# Color Editor For Brian's Depth Colorizer VS Extension"

        [<Microsoft.FSharp.Core.DefaultValue>] 
        val mutable private edgeColor : Color

        [<Microsoft.FSharp.Core.DefaultValue>] 
        val mutable private mainColor : Color

        [<Microsoft.FSharp.Core.DefaultValue>]
        val mutable private selectedRects : Rectangle * Rectangle    
    
        static let  edgeColorProperty =
                DependencyProperty.Register("EdgeColor", typeof<Color>, typeof<MainWindow>,
                    new FrameworkPropertyMetadata(Colors.Silver, 
                        FrameworkPropertyMetadataOptions.AffectsRender,
                        new PropertyChangedCallback(fun depObj e ->
                            match depObj, e.NewValue with
                            | (:? MainWindow as mw), (:? Color as c) -> 
                                (fst mw.selectedRects).Fill <- SolidColorBrush(c)
                                mw.IsDirty <- true
                            | _ -> ())))
        static  member EdgeColorProperty = edgeColorProperty

        static let mainColorProperty =
                DependencyProperty.Register("MainColor", typeof<Color>, typeof<MainWindow>,
                    new FrameworkPropertyMetadata(Colors.Silver, 
                        FrameworkPropertyMetadataOptions.AffectsRender,
                        new PropertyChangedCallback(fun depObj e ->
                            match  depObj,  e.NewValue with
                            | (:? MainWindow as mw), (:? Color as c) -> 
                                (snd mw.selectedRects).Fill <- SolidColorBrush(c)
                                mw.IsDirty <- true
                            | _ -> ())))        
        static  member MainColorProperty = mainColorProperty

        let makeBinding(sourceObj:obj, sourcePath:string, 
                        targetObj:DependencyObject, targetDependencyProperty:DependencyProperty, mode : BindingMode ) =
            let b = new Binding()
            b.Source <- sourceObj
            b.Mode <- mode
            b.Path <- PropertyPath(sourcePath)   
            BindingOperations.SetBinding(targetObj, targetDependencyProperty, b) |> ignore

        let headerLabel text =
            new Label(Content=text, Margin=Thickness(5.,2.,5.,1.), Background=Brushes.Cornsilk, 
                                        HorizontalAlignment=HorizontalAlignment.Stretch, Foreground = Brushes.Blue, FontWeight = FontWeights.ExtraBold)
    
        let buttonNames = [| "New"; "|"; "Open"; "|"; "Save"; "Save As"; "|"; "Delete"; "|"; "Apply" |]
        let tooltips = [| "New (Ctrl+N)"; "|"; "Open (Ctrl+O)"; "|"; "Save (Ctrl+S)"; "Save As"; "|"; "Delete (Del)\nDelete the color file."; "|"; "Apply the color scheme.\nThe data will be added to registry." |]
        let commands : ICommand [] = 
                [|          
                    ApplicationCommands.New;
                    unbox<ICommand> null;        
                    ApplicationCommands.Open;
                    unbox<ICommand> null;
                    ApplicationCommands.Save;                
                    ApplicationCommands.SaveAs;
                    unbox<ICommand> null;
                    ApplicationCommands.Delete;
                    unbox<ICommand> null;
                    Commands.ApplyCommand;                          
                |]

        let toolBarBrush = (BrushConverter()).ConvertFromString("#FF5E6A93") :?> SolidColorBrush
        let buildToolbar (names:string[]) (commands:ICommand[]) (tooltips:string[]) =        
            let createButton cmd name tooltip: Control = 
                match name with
                | "|" -> new Separator() :> Control
                | _ ->
                    let button = new Button()
                    button.Command <- cmd
                    ToolTipService.SetToolTip(button,ToolTip(Content=tooltip))
                    ToolTipService.SetShowOnDisabled(button,true)                        
                    button.Content <- new Image(Source = BitmapImage(Uri("pack://application:,,,/ColorizerEditor;component/images/" + name + ".png")), Stretch = Stretch.None)
                    button :> Control       
            let tb = new ToolBar(Background = toolBarBrush, Margin = Thickness(5.,2.,5.,2.), HorizontalAlignment = HorizontalAlignment.Stretch)                            
            let toolbar =
                (Array.zip3 names commands tooltips)
                |> Array.fold (fun (acc:ToolBar) (n,c,t) -> acc.Items.Add(createButton c n t) |> ignore ; acc) tb         
            toolbar

        let grayScaleColor =
            [|  
                190uy,190uy,190uy,230uy,230uy,230uy
                170uy,170uy,170uy,210uy,210uy,210uy
                184uy,184uy,184uy,224uy,224uy,224uy
                164uy,164uy,164uy,204uy,204uy,204uy
                178uy,178uy,178uy,218uy,218uy,218uy
                158uy,158uy,158uy,198uy,198uy,198uy
                172uy,172uy,172uy,212uy,212uy,212uy
                152uy,152uy,152uy,192uy,192uy,192uy
                166uy,166uy,166uy,206uy,206uy,206uy
                146uy,146uy,146uy,186uy,186uy,186uy
                |]
                
        let colors =
            try
                let key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\VisualStudio\10.0\Text Editor\FSharpDepthColorizer")
                Array.init 10 (fun i -> key.GetValue(sprintf "Depth%d" i) :?> string)
                |> Array.map  (fun s -> let [|r1;g1;b1;r2;g2;b2|] = s.Split[|','|] |> Array.map byte 
                                        r1,g1,b1,r2,g2,b2)
            with _ -> grayScaleColor            
    
        (* Just enough for happy flow :) *)
        let readColorFile path : (bool * (byte * byte * byte * byte * byte * byte)[])   =
            let dv = false , (Array.empty<byte * byte * byte * byte * byte * byte>)  
            try           
                if File.Exists(path) then
                    let data = File.ReadAllLines(path) 
                                |> Array.filter (fun x -> x.Contains("="))
                                |> Array.map (fun x -> (x.Split[|'='|].[0]).[1].Replace("\"","").Trim())
                                |> Array.map (fun x -> 
                                    let [|r1;g1;b1;r2;g2;b2|] = x.Split[|','|] |> Array.map byte 
                                    r1,g1,b1,r2,g2,b2)
                    true,data                                                    
                else dv                                
            with _ -> dv 
                                 
        let setColor (colorData : (byte * byte * byte * byte * byte * byte)[]) =
            rightPane.Children.Clear()
            rects.Clear()
            let allColor =  [|
                                    for i in 0..colorData.Length - 1 do
                                        let (r1,g1,b1,r2,g2,b2) = colorData.[i]
                                        yield ( new SolidColorBrush(Color.FromRgb(r1,g1,b1)),
                                                new SolidColorBrush(Color.FromRgb(r2,g2,b2)))
                                |]        
            let factor = 30.        
            for i in 0..allColor.Length - 1 do            
                let offset = (float i) + 1.
                let eRect = new Rectangle(Width=1500., Height=1000., Fill = (fst allColor.[i]), Name = "e" + i.ToString())            
                Canvas.SetLeft(eRect, offset * factor)
                Canvas.SetTop(eRect, offset * factor)
                Canvas.SetZIndex(eRect, i)
                rightPane.Children.Add(eRect) |> ignore

                let mRect = new Rectangle(Width=1500., Height=1000., Fill = (snd allColor.[i]), Name = "m" + i.ToString())            
                Canvas.SetLeft(mRect, offset * factor + 5.)
                Canvas.SetTop(mRect, offset * factor)
                Canvas.SetZIndex(mRect, i + 1)
                rightPane.Children.Add(mRect) |> ignore

                rects.Add((eRect,mRect))

            let er,mr = rects.Item(0)
            self.selectedRects <- er,mr
        
            edgeColorPicker.SelectedColor <- (er.Fill :?> SolidColorBrush).Color
            mainColorPicker.SelectedColor <- (mr.Fill :?> SolidColorBrush).Color

            makeBinding(edgeColorPicker, "SelectedColor", self, MainWindow.EdgeColorProperty, BindingMode.TwoWay)
            makeBinding(mainColorPicker, "SelectedColor", self, MainWindow.MainColorProperty, BindingMode.TwoWay)

        let getColorData() =
            let sb = new StringBuilder()
            let appendLine = sb.AppendLine >> ignore        
            appendLine "Windows Registry Editor Version 5.00"        
            appendLine "[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\10.0\Text Editor\FSharpDepthColorizer]"
            for i in 0..rects.Count - 1 do
                let (er : Rectangle , mr : Rectangle) = rects.[i]
                let ec = (er.Fill :?> SolidColorBrush).Color
                let mc = (mr.Fill :?> SolidColorBrush).Color
                appendLine <| sprintf "\"Depth%d\"=\"%d,%d,%d,%d,%d,%d\"" i ec.R ec.G ec.B mc.R mc.G mc.B
            sb.ToString()

        let writeToRegistry() = 
            try
                let baseKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\VisualStudio\10.0\Text Editor", true)
                (* Ref: http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.registrysecurity.aspx *)
                let user = Environment.UserDomainName + "\\" + Environment.UserName            
                let regSecurity = new RegistrySecurity()
                let rule = new RegistryAccessRule(user, RegistryRights.ReadKey ||| RegistryRights.WriteKey ||| RegistryRights.Delete,
                                InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow)
                regSecurity.AddAccessRule(rule)
                use targetKey = baseKey.CreateSubKey("FSharpDepthColorizer", RegistryKeyPermissionCheck.ReadWriteSubTree, regSecurity)
                for i in 0..rects.Count - 1 do
                    let (er : Rectangle , mr : Rectangle) = rects.[i]
                    let ec = (er.Fill :?> SolidColorBrush).Color
                    let mc = (mr.Fill :?> SolidColorBrush).Color
                    targetKey.SetValue("Depth" + i.ToString(), sprintf  "%d,%d,%d,%d,%d,%d" ec.R ec.G ec.B mc.R mc.G mc.B, RegistryValueKind.String)                
            with e ->            
                showError(e.Message)
        
        let overwrite path =
            let mutable result = false
            try
                use f = new FileStream(path, FileMode.Create)
                use writer = new StreamWriter(f)
                writer.Write(getColorData())
                writer.Flush()
                writer.Close()
                result <- true  
            with
                | :? IOException -> 
                    showWarning("Sorry, there was an error saving the file.\nPlease try again.")
                    result <- false
            result

        let xmlFilePath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\FSharpDepthColorizer.xml";
        let saveToXml (path:String) =
            if not <| File.Exists(xmlFilePath) then
                let xdoc = new XDocument(Declaration = XDeclaration("1.0", "utf-8", "yes"));
                let rootElement = new XElement(XName.Get("Files"))
                rootElement.Add(new XElement(XName.Get("File"),path))
                xdoc.Add(rootElement)
                xdoc.Save(xmlFilePath)
            else
                let xdoc = XDocument.Load(xmlFilePath)
                let root = xdoc.Elements() |> Seq.head                
                if not (root.Elements() |> Seq.exists (fun x -> x.Value.Equals(path,StringComparison.OrdinalIgnoreCase))) then 
                    root.Add(new XElement(XName.Get("File"),path))
                    xdoc.Save(xmlFilePath)
        
        let addTreeViewItem path =                 
            let item = new TreeViewItem(Header = System.IO.Path.GetFileNameWithoutExtension(path), ToolTip = path)
            if not <| fileExplorerTree.Items.Contains(rootItem) then   
                fileExplorerTree.Items.Add(rootItem) |> ignore                           
            rootItem.Items.Add(item) |> ignore        
    
        let asyncLoad = 
            async
                {
                    let xdoc = XDocument.Load(xmlFilePath)                                    
                    if (Seq.isEmpty >> not) <| xdoc.Elements() then
                        System.Threading.SynchronizationContext.SetSynchronizationContext(System.Windows.Threading.DispatcherSynchronizationContext(Application.Current.Dispatcher))
                        do! Async.SwitchToContext(System.Threading.SynchronizationContext.Current)
                        let rootElement =  xdoc.Elements()  |> Seq.head
                        rootElement.Elements() |> Seq.iter (fun x -> addTreeViewItem x.Value)
                }

        let populateFileExplorer() =
            if File.Exists(xmlFilePath) then            
                Async.Start(asyncLoad)                                   
                                                              
        let save() : (bool*string) =
            let dialog = new SaveFileDialog()
            dialog.DefaultExt <- ".fun"
            dialog.Filter <- "Color File (.fun)|*.fun" 
            dialog.FileName <- "FSColor"
            dialog.RestoreDirectory <- true                        
            let r = dialog.ShowDialog()
            let mutable result = false
            let mutable savePath = String.Empty
            if r.HasValue && r.Value = true  then    
                try                     
                    use sr = new StreamWriter(dialog.FileName,false)
                    sr.Write(getColorData())    
                    sr.Flush()     
                    sr.Close()                     
                    result <- true   
                    savePath <- dialog.FileName                   
                with
                | :? IOException -> 
                    showWarning("Sorry, there was an error saving the file.\nPlease try again." )
                    result <- false
            result, savePath

        let deleteFile() =
            let selectedItem = unbox<TreeViewItem> fileExplorerTree.SelectedItem;
            match selectedItem with
            | null -> ()
            | _  ->
                if askQuestion("Are you sure to delete the file?", "Delete") = MessageBoxResult.Yes then                                            
                    if File.Exists(currentSavePath) then File.Delete(currentSavePath)                        
                    let xdoc = XDocument.Load(xmlFilePath)
                    let root = xdoc.Elements() |> Seq.head
                    let delItem = root.Elements() |> Seq.find (fun x -> x.Value = currentSavePath)
                    if not (delItem = null) then 
                        delItem.Remove()
                        xdoc.Save(xmlFilePath)
                    rootItem.Items.Remove(selectedItem)
                    setColor grayScaleColor
                    currentSavePath <- String.Empty
                    self.Title <- title      
        
        let saveColorFile() =
            if isDirty && currentSavePath = String.Empty then
                let result, savePath = save()
                isDirty <- not result
                currentSavePath <- savePath
                if result then
                    self.Title <- self.Title + " - " + currentSavePath
                    addTreeViewItem currentSavePath
                    saveToXml currentSavePath                            
            elif isDirty then
                isDirty <- overwrite currentSavePath 

        let askForSaving()  =
            if isDirty && currentSavePath = String.Empty then
                if askQuestion("Do you want to save the current data?", "Alert") = MessageBoxResult.Yes then
                    let result, savePath = save()
                    isDirty <- not result
                    currentSavePath <- savePath
                    if result then
                        self.Title <- self.Title + " - " + currentSavePath
                        addTreeViewItem currentSavePath
                        saveToXml currentSavePath                            
            elif isDirty then
                isDirty <- overwrite currentSavePath
           

        let newFile()=
            askForSaving()       
            setColor grayScaleColor
            isDirty <- true
            self.Title <- title
            currentSavePath <- String.Empty
            if not (fileExplorerTree.SelectedItem = null) then
                (fileExplorerTree.SelectedItem :?> TreeViewItem).IsSelected <- false          

        let openFile() =            
            let dialog = new OpenFileDialog()
            dialog.DefaultExt <- ".fun"
            dialog.Filter <- "Color File (.fun)|*.fun" 
            dialog.FileName <- "FSColor"
            dialog.RestoreDirectory <- true
            let r = dialog.ShowDialog()
            if r.HasValue && r.Value = true  then  
                askForSaving()  
                match readColorFile(dialog.FileName) with
                | true , r -> 
                    setColor r
                    saveToXml dialog.FileName
                    currentSavePath <- dialog.FileName
                    self.Title <- title + " - " + currentSavePath
                    if not (fileExplorerTree.SelectedItem = null) then
                        (fileExplorerTree.SelectedItem :?> TreeViewItem).IsSelected <- false
                | _ -> showWarning("File \"" + dialog.FileName + "\" cannot be read. Please check all the necessary things.")             
        do        
            self.Title <- title 
            self.Icon <- BitmapImage(Uri("pack://application:,,,/ColorizerEditor;component/Images/App.png"))
            let rootLayout = new Grid()
            rootLayout.RowDefinitions.Add(RowDefinition(Height=GridLength(0.,GridUnitType.Auto)))
            rootLayout.RowDefinitions.Add(RowDefinition(Height=GridLength(1.,GridUnitType.Star)))
            rootLayout.ColumnDefinitions.Add(ColumnDefinition(Width = GridLength(1.,GridUnitType.Star)))
            rootLayout.ColumnDefinitions.Add(ColumnDefinition(Width = GridLength(2.0)))
            rootLayout.ColumnDefinitions.Add(ColumnDefinition(Width = GridLength(2.,GridUnitType.Star)))
        
            let toolbar = buildToolbar buttonNames commands tooltips
            Grid.SetRow(toolbar,0)
            Grid.SetColumnSpan(toolbar,3)
            Grid.SetColumn(toolbar,0)
            rootLayout.Children.Add(toolbar) |> ignore

            let leftPane = new StackPanel()
            Grid.SetColumn(leftPane,0)
            Grid.SetRow(leftPane,1)
            let tabControl = new TabControl(Margin = Thickness(5., 0., 5., 0.), VerticalAlignment = VerticalAlignment.Stretch)        
            let colorpickerTab = new TabItem(Header = "Color Selectors")
            let fileExplorerTab = new TabItem(Header = "Color File Explorer")
            let addtab = tabControl.Items.Add >> ignore
            addtab colorpickerTab
            addtab fileExplorerTab             
            let colorpickerGrid = new Grid(VerticalAlignment = VerticalAlignment.Stretch)
            colorpickerGrid.RowDefinitions.Add(RowDefinition(Height = GridLength(320.,GridUnitType.Pixel)))        
            colorpickerGrid.RowDefinitions.Add(RowDefinition(Height = GridLength(320.,GridUnitType.Pixel)))        
            colorpickerGrid.RowDefinitions.Add(RowDefinition(Height = GridLength(0.,GridUnitType.Auto)))        
            Grid.SetColumn(colorpickerGrid,0)
            Grid.SetRow(colorpickerGrid,1)

            let edgeColorPanel = new StackPanel(Orientation = Orientation.Vertical, Margin = Thickness(0.,10.,0.,0.))
            let edgeHeader = headerLabel "Edge Color"
            edgeColorPanel.Children.Add(edgeHeader) |> ignore        
            edgeColorPanel.Children.Add(edgeColorPicker) |> ignore
            Grid.SetRow(edgeColorPanel,0)
            colorpickerGrid.Children.Add(edgeColorPanel) |> ignore

            let mainColorPanel = new StackPanel(Orientation = Orientation.Vertical, Margin = Thickness(0.,20.,0.,0.))
            let mainHeader = headerLabel "Main Color"
            mainColorPanel.Children.Add(mainHeader) |> ignore        
            mainColorPanel.Children.Add(mainColorPicker) |> ignore
            Grid.SetRow(mainColorPanel,1)
            colorpickerGrid.Children.Add(mainColorPanel) |> ignore            
            colorpickerTab.Content <- colorpickerGrid
                              
            fileExplorerTab.Content <- fileExplorerTree        
            self.Loaded.Add(fun _ -> populateFileExplorer())
            fileExplorerTree.SelectedItemChanged.Add(fun x ->
                    match x.NewValue with
                    | :? TreeViewItem as item when not (item = rootItem) ->
                        match readColorFile(item.ToolTip.ToString()) with
                        | true , r -> 
                            setColor r
                            currentSavePath <- item.ToolTip.ToString()
                            self.Title <- title + " - " + currentSavePath
                        | _ -> showWarning("File \"" + item.ToolTip.ToString() + "\" cannot be read. Please check all the necessary things.")        
                    | _ -> ()
                )

            leftPane.Children.Add(tabControl) |> ignore                                             
            rootLayout.Children.Add(leftPane) |> ignore
        
            let gridSplitter = new GridSplitter(HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch, Background = toolBarBrush)
            Grid.SetColumn(gridSplitter,1)
            Grid.SetRow(gridSplitter,1)
            rootLayout.Children.Add(gridSplitter) |> ignore
                
            Grid.SetColumn(rightPane,2)
            Grid.SetRow(rightPane,1)
            rootLayout.Children.Add(rightPane) |> ignore

            self.Content <- rootLayout
            setColor colors

            (* CommandBinding For NewCommand *)
            self.CommandBindings.Add(
                new CommandBinding(
                    ApplicationCommands.New,
                    (fun s (e:ExecutedRoutedEventArgs ) ->  newFile()),                
                    (fun s (e:CanExecuteRoutedEventArgs ) -> e.CanExecute <- true))) |> ignore

            (* CommandBinding For OpenCommand *)
            self.CommandBindings.Add(
                new CommandBinding(
                    ApplicationCommands.Open,
                    (fun s (e:ExecutedRoutedEventArgs ) ->  openFile()),                
                    (fun s (e:CanExecuteRoutedEventArgs ) -> e.CanExecute <- true))) |> ignore
                                                            
            (* CommandBinding For ApplyCommand *)
            self.CommandBindings.Add(
                new CommandBinding(
                    Commands.ApplyCommand,
                    (fun s (e:ExecutedRoutedEventArgs ) ->  writeToRegistry()),                
                    (fun s (e:CanExecuteRoutedEventArgs ) -> e.CanExecute <- true))) |> ignore

            (* CommandBinding For SaveCommand *)
            self.CommandBindings.Add(
                new CommandBinding(
                    ApplicationCommands.Save,
                    (fun s e -> saveColorFile()),
                    (fun s (e:CanExecuteRoutedEventArgs ) -> e.CanExecute <- true))) |> ignore
        
            (* CommandBinding For SaveAsCommand *)
            self.CommandBindings.Add(
                new CommandBinding(
                    ApplicationCommands.SaveAs,
                    (fun s e ->  
                        let result, savePath = save()
                        isDirty <- result
                        currentSavePath <- savePath
                        if result then 
                            self.Title <- self.Title + " - " + currentSavePath
                            addTreeViewItem currentSavePath
                            saveToXml currentSavePath 
                    ),
                    (fun s (e:CanExecuteRoutedEventArgs ) -> e.CanExecute <- true))) |> ignore

            (* CommandBinding For DeleteCommand *)
            self.CommandBindings.Add(
                new CommandBinding(
                    ApplicationCommands.Delete,
                    (fun s e -> deleteFile() ),
                    (fun s (e:CanExecuteRoutedEventArgs ) -> 
                        e.CanExecute <-  match fileExplorerTree.SelectedItem with
                                            | null -> false
                                            | item when item = box rootItem -> false
                                            | _ -> true))) |> ignore

        override  self.OnMouseDown e =
            match e.OriginalSource with
            | :? Rectangle as oRect when (System.String.IsNullOrWhiteSpace >> not) oRect.Name ->                 
                    let edge,main = Seq.find (fun (x:Rectangle,y:Rectangle) -> x.Name = oRect.Name || y.Name = oRect.Name) rects    
                    self.selectedRects <- edge,main
                    self.EdgeColor <- (edge.Fill :?> SolidColorBrush).Color
                    self.MainColor <- (main.Fill :?> SolidColorBrush).Color
            | _ -> ()

        member self.MainColor 
                with get() = self.GetValue(MainWindow.MainColorProperty) :?> Color
                and set c = self.SetValue(MainWindow.MainColorProperty,c)
    
        member self.EdgeColor 
                with get() = self.GetValue(MainWindow.EdgeColorProperty) :?> Color
                and set c = self.SetValue(MainWindow.EdgeColorProperty,c)

        member self.IsDirty 
                with get() = isDirty
                and set c = isDirty <- c    

module StartUp = 
    [<System.STAThread>]
    do        
        (new Application()).Run(MainWindow()) |> ignore
        